<?php
error_reporting(E_ALL);
interface Rule{
	function getRule();
}

abstract class Flag{
	protected $_flag = array();
	public function setChain(){
		$this -> _flag["chain"] = "C";
	}
	public function setCookie($name, $value, $domain, $lifetime = "", $path = ""){
		$list = array($name, $value, $domain, $lifetime, $path);
		$this -> _flag["cookie"] = "CO=" . implode(":", $list);
	}
	public function setEnv($name, $value){
		$this -> _flag["env"] = "E=$name:$value";
	}
	public function setForbidden(){
		$this -> _flag["forbidden"] = "F";
	}
	public function setGone(){
		$this -> _flag["gone"] = "G";
	}
	public function setHandler($mimetype){
		$this -> _flag["handler"] = "H:$mimetype";
	}
	public function setLast(){
		$this -> _flag["last"] = "L";
	}
	public function setNext(){
		$this -> _flag["next"] = "N";
	}
	public function setNoCase(){
		$this -> _flag["nocase"] = "NC";
	}
	public function setNoEscape(){
		$this -> _flag["noescape"] = "NE";
	}
	public function setNoSubrequest(){
		$this -> _flag["nosubrequest"] = "NS";
	}
	public function setPassThru(){
		$this -> _flag["passthru"] = "PT";
	}
	public function setQueryStringAppend(){
		$this -> _flag["querystringappend"] = "QSA";
	}
	public function setRedirect($code = ""){
		$this -> _flag["redirect"] = "R";
		if ($code != "")
			$this -> _flag["redirect"] .= "=$code";
	}
	public function setSkip(){	
		$this -> _flag["skip"] = "S";
	}
	public function setType($mimetype){
		$this -> setHandler($mimetype);
	}
}

// TODO Flag Proxy

class RewriteRule extends Flag{
	private $_pattern;
	private $_target;
	private $_keyword = "RewriteRule";
	public function __construct($pattern, $target){
		$this -> _pattern = $pattern;
		$this -> _target = $target;
	}	
	public function getRule(){
		$flags = "";
		if (is_array($this -> _flag))
			$flags = implode(",", $this -> _flag);	
		
		$rule = $this -> _keyword . "\t" . $this -> _pattern . "\t" .  $this -> _target;
		if ($flags != "")
			$rule .= "\t[" . $flags . "]";
		return $rule;
	}
	
}
class ErrorDocument  implements Rule{
	private $_keyword = "ErrorDocument";
	private $_code = "";
	private $_page;
	public function __construct($code, $page){
		$this -> _code = $code;
		$this -> _page = $page;
	}
	public function getRule(){
		return $this -> _keyword . "\t" . $this -> _code . "\t" . $this -> _page; 
	}
}
class RewriteBase  implements Rule{
	private $_base;
	private $_keyword = "RewriteBase";
	public function __construct($base){
		$this -> _base = $base;
	}
	public function getRule(){
		return $this -> _keyword . "\t" . $this -> _base; 
	}
}
class Options  implements Rule{
	private $_keyword = "Options";
	private $_flags;
	public function __construct($flags = null){
		if (is_array($flags)){
			$this -> _flags = $flags;
		}
	}
	public function setOption($name){
		if (!is_array($name, $this -> _flags)){
			$this -> _flags[] = $name;
		}
	}
	public function getRule(){
		return $this -> _keyword . "\t" . implode(" ", $this -> _flags); 
	}
}

class Comment  implements Rule{
	private $_type;
	private $_text;
	private $_keyword = "#";
	public function __construct($type = "simple", $text = ""){
		$this -> _type = $type;
		$this -> _text = $text;
	}
	public function getRule(){
		
		switch($this -> _type){
			case "simple":
				return "#\t" . $this -> _text;
			case "section":
				return "=============================================================================#
          ".$this -> _text."
=============================================================================#\n"; 
			case "title":
				return "\n## ".$this -> _text." ###\n";
			case "subtitle":
				return "\n======== ".$this -> _text."\n";
		}
	}
}
class RewriteEngine implements Rule{
	private $_active = true;
	private $_keyword = "RewriteEngine";
	public function __construct($active = true){
		$this -> _active = $active;
	}
	public function getRule(){
		if ($this -> _active)
			return $this -> _keyword . "\tOn";
		return $this -> _keyword . "\tOff";	 
	}
}

class RewriteCond extends Flag{
	private $_keyword = "RewriteCond";
	private $_testString;
	private $_pattern;
	public function __construct($testString, $pattern){
		$this -> _testString = $testString;
		$this -> _pattern = $pattern;
	}
	public function getRule(){
		$flags = "";
		$flags = implode(",", $this -> _flag);
		if ($flags != "") $flags = "[$flags]";
		return $this -> _keyword . "\t" . $this -> _testString . "\t" . $this -> _pattern ."\t" . $flags;	 
	}
}

class RewriteCore{
	private $_rules;
	public function __construct(){
		$this -> _rules = array();
	}
	private function makeKey(array $params){
		$key = implode("_", $params);
		return sha1($key);
	}
	public function addRewriteEngine($active = true){
		$key = $this -> makeKey(array(time()));
		$this -> _rules[$key] = new RewriteEngine($active);
	}
	public function addRewriteRule($pattern, $target){
		$key = $this -> makeKey(array($pattern,$target));
		$this -> _rules[$key] = new RewriteRule($pattern, $target);
		return $key;
	}
	public function addRewriteCond($testString, $pattern){	
		$key = $this -> makeKey(array($testString, $pattern));
		$this -> _rules[$key] = new RewriteCond($testString, $pattern);
		return $key;
	}
	public function addRewriteBase($base){
		$key = $this -> makeKey(array($base));
		$this -> _rules[$key] = new RewriteBase($base);
	}
	public function addSectionComment($text){
		$key = $this -> makeKey(array("section", $text));
		$this -> _rules[$key] = new Comment("section", $text);
	}
	public function addTitleComment($text){
		$key = $this -> makeKey(array("title", $text));
		$this -> _rules[$key] = new Comment("title", $text);
	}
	public function addSubtitleComment($text){
		$key = $this -> makeKey(array("subtitle", $text));
		$this -> _rules[$key] = new Comment("subtitle", $text);
	}
	
	public function addErrorDocument($code, $page){
		$key = $this -> makeKey(array($code, $page));
		$this -> _rules[$key] = new ErrorDocument($code, $page);
	}
	public function addOptions($flag){
		$key = $this -> makeKey(array($flag));
		$this -> _rules[$key] = new Options($flag);
	}
	public function appendOptions($key, $flag){
		$option = $this -> _rules[$key];
		$option -> setOption($flag);
	}
	public function setChain($key){
		$rule = $this -> _rules[$key];
		$rule -> setChain();
	}
	
	public function setCookie($key, $name, $value, $domain, $lifetime = "", $path = ""){
		$rule = $this -> _rules[$key];
		$rule -> setCookie($key, $name, $value, $domain, $lifetime, $path);
	}
	public function setEnv($key, $name, $value){
		$rule = $this -> _rules[$key];
		$rule -> setEnv($key, $name, $value);
	}
	public function setForbidden($key){
		$rule = $this -> _rules[$key];
		$rule -> setForbidden($key);
	}
	public function setGone($key){
		$rule = $this -> _rules[$key];
		$rule -> setGone($key);
	}
	public function setHandler($key, $mimetype){
		$rule = $this -> _rules[$key];
		$rule -> setHandler($key, $mimetype);
	}
	public function setLast($key){
		$rule = $this -> _rules[$key];
		$rule -> setLast();
	}
	public function setNext($key){
		$rule = $this -> _rules[$key];
		$rule -> setNext();
	}
	public function setNoCase($key){
		$rule = $this -> _rules[$key];
		$rule -> setNoCase();
	}
	public function setNoEscape($key){
		$rule = $this -> _rules[$key];
		$rule -> setNoEscape();
	}
	public function setNoSubrequest($key){
		$rule = $this -> _rules[$key];
		$rule -> setNoSubrequest();
	}
	public function setPassThru($key){
		$rule = $this -> _rules[$key];
		$rule -> setPassThru();
	}
	public function setQueryStringAppend($key){
		$rule = $this -> _rules[$key];
		$rule -> setQueryStringAppend();
	}
	public function setRedirect($key, $code = ""){
		$rule = $this -> _rules[$key];
		$rule -> setRedirect($code);
	}
	public function setSkip($key){	
		$rule = $this -> _rules[$key];
		$rule -> setSkip();
	}
	public function setType($key, $mimetype){
		$this -> setHandler($key, $mimetype);
	}
	public function output(){
		$htaccess = "";
		foreach($this -> _rules as $rule){
			$htaccess .= $rule -> getRule() . "\n"; 
		}
		print_R($this);
		return $htaccess;
	}
}
class PhpRewrite extends RewriteCore{
	function __construct($autoRewrite = false){
		parent::__construct();
		if ($autoRewrite)
			$this -> addRewriteEngine();
	}
	function defaultSetting(){
		$this -> addTitleComment("DEFAULT SETTING");
		$this -> addOptions(array("+ExecCGI", "-Indexes"));
	}
	function permaRedirect($from, $to){
		$rule = $this -> addRewriteRule($from, $to);
		$this -> setRedirect($rule, "301");
	}
	function antiHotlink($domain, $stopImage = ""){
		$this -> addTitleComment("IMAGE HOTLINK PREVENT");
		$this -> addRewriteCond("%{HTTP_REFERER}","!^$");
		$rule = $this -> addRewriteCond("%{HTTP_REFERER}","!^http://(www\.)?".str_replace(".","\.", $domain)."/.*$");
		$this -> setNocase($rule);
		if ($stopImage != ""){
			$rule = $this -> addRewriteRule("\.(gif|jpg)$", $stopImage);
			$this -> setRedirect($rule);
			$this -> setLast($rule);
		}else{
			$rule = $this -> addRewriteRule("\.(gif|jpg)$","-");
			$this -> setForbidden($rule);
		}
	}
	function error404($url){
		$this -> addSubtitleComment("404");
		$this -> addErrorDocument("404", $url);
	}
}

$htaccess = new PhpRewrite();
$htaccess -> addSectionComment("MAIN SETTINGS AND OPTIONS");
$htaccess -> defaultSetting();
$htaccess -> addRewriteEngine();
$htaccess -> antiHotlink("grafikando.com", "http://www.grafikando.com/stop.gif");
$htaccess -> error404("/404.html");
echo $htaccess -> output();
?>
